import axios from "axios-miniprogram";
import {
  showToast,
  cache,
  showLoading,
  router,
  showConfirmDialog,
} from "@/util/index";
// ======== 基础配置 ========
const BASE_URL = "https://api.squirrelrecycle.cloud";

// ======== Axios 实例及默认配置 ========
const service = axios.create({
  baseURL: BASE_URL,
  timeout: 8000, // 请求超时时间
  headers: {
    "Content-Type": "application/json;charset=UTF-8",
  },
  // 仅当 HTTP 状态码为 2xx 时，Promise 才被认为是 fulfilled
  validateStatus: (status) => status >= 200 && status < 300,
});

// ======== Token 相关本地存储操作 (保持不变) ========
function getToken(): string {
  return cache.get("token");
}

function setToken(token: string) {
  cache.set("token", token);
}

function setTokenExpired(timestamp: number) {
  cache.set("token_expired", timestamp);
}

// ======== Axios 请求拦截器 ========
service.interceptors.request.use(
  (config: any) => {
    if (config.requireAuth !== false) {
      const token = getToken();
      if (token) {
        config.headers["token"] = token;
      } else {
        // showToast("登录才能访问");
        router.navigateTo("/pages/login/index");
      }
    }
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    console.error("Request Error:", error);
    return Promise.reject(error);
  }
);

// ======== Axios 响应拦截器 ========
service.interceptors.response.use(
  /**
   * HTTP 状态码为 2xx 时，会进入这里
   */
  (response) => {
    wx.hideLoading();
    const res = response.data; // 后端返回的完整数据: {code, data, message, timestamp}

    // **核心逻辑：检查并更新后端下发的新Token**
    // 无论业务成功与否，只要后端返回了 newToken，就更新它
    if (
      res.data &&
      res.data.newToken &&
      res.data.newToken.token &&
      res.data.newToken.tokenExpired
    ) {
      setToken(res.data.newToken.token);
      setTokenExpired(res.data.newToken.tokenExpired);
      delete res.data.newToken;
    }

    // 根据业务码 code 进行判断
    switch (res.code) {
      case 200:
        // 请求成功
        if (response.config.showSuccessMessage) {
          showToast(res.message || "操作成功", 1500);
        }
        if (res.data && res.data.main) return res.data.main;
        // 返回核心业务数据
        return res.data;
      case 401:
        // 未授权，登录状态失效
        showToast(res.message || "登录已失效，请重新登录");
        // 清除本地过期的登录信息
        setToken("");
        setTokenExpired(0);
        router.navigateTo("/pages/login/index");
        return Promise.reject(res);
      case 403:
        // 无权限操作
        showToast(res.message || "无权访问此内容");
        return Promise.reject(res);
      default:
        // 其他业务错误
        showToast(res.message || "服务器错误");
        return Promise.reject(res);
    }
  },
  /**
   * HTTP 状态码不为 2xx 时，或发生其他网络错误（如超时），会进入这里
   */
  (error) => {
    wx.hideLoading();
    console.error("Axios Response Error:", error);
    let errorMessage = "网络异常，请检查您的网络连接";
    if (error.message.includes("timeout")) {
      errorMessage = "请求超时，请稍后再试";
    } else if (error.response) {
      // 服务器返回了非2xx的错误状态码
      // 在我们的设计中，这种情况较少，因为后端统一返回200，用code区分
      // 但为了健壮性，仍然处理
      errorMessage = `请求错误: ${error.response.status}`;
    }
    showToast(errorMessage);
    return Promise.reject(error);
  }
);

// ======== 统一请求函数封装 ========

/**
 * 定义请求配置项接口
 */
interface RequestOptions {
  /** 是否需要认证，默认为 true */
  requireAuth?: boolean;
  /** 是否显示加载提示，可以为布尔值或 wx.showLoading 的配置对象 */
  loading?: boolean | WechatMiniprogram.ShowLoadingOption;
  /** 请求成功时（code=200），是否显示后端返回的 message 提示，默认为 true */
  showSuccessMessage?: boolean;
  /** 自定义请求头 */
  headers?: object;
}

/**
 * 发起POST请求
 * @param url 请求路径
 * @param data 请求体数据
 * @param options 请求配置项
 * @returns Promise<any> 返回后端响应的 data 字段
 */
export function request(
  url: string,
  data: object = {},
  options: RequestOptions = {}
): Promise<any> {
  // 处理默认配置
  const config: RequestOptions = {
    requireAuth: true,
    loading: false, // 默认不显示loading
    showSuccessMessage: true, // 默认显示成功提示
    ...options,
  };

  // 处理 loading
  if (config.loading) {
    const loadingOptions: WechatMiniprogram.ShowLoadingOption = {
      title: "加载中...",
      mask: true,
    };
    // 如果传入的是对象，则合并配置
    if (typeof config.loading === "object") {
      Object.assign(loadingOptions, config.loading);
    }
    showLoading(loadingOptions);
  }

  return service({
    url,
    method: "POST",
    data,
    headers: config.headers,
    requireAuth: config.requireAuth,
    showSuccessMessage: config.showSuccessMessage,
  });
}
